package com.scheduling.inventory.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.scheduling.common.exception.BusinessException;
import com.scheduling.inventory.dto.ProductInventoryDTO;
import com.scheduling.inventory.dto.ProductInventoryQueryDTO;
import com.scheduling.inventory.entity.ProductInventory;
import com.scheduling.inventory.mapper.ProductInventoryMapper;
import com.scheduling.inventory.service.ProductInventoryService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 产品库存Service实现类
 *
 * @author 开发团队
 * @since 2025-05-29
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class ProductInventoryServiceImpl extends ServiceImpl<ProductInventoryMapper, ProductInventory>
        implements ProductInventoryService {

    private final ProductInventoryMapper productInventoryMapper;

    @Override
    public IPage<ProductInventoryDTO> getInventoryPage(ProductInventoryQueryDTO queryDTO) {
        log.info("分页查询产品库存，查询条件：{}", queryDTO);

        Page<ProductInventory> page = new Page<>(queryDTO.getCurrent(), queryDTO.getSize());
        IPage<ProductInventory> inventoryPage = productInventoryMapper.selectPageWithProduct(page, queryDTO);

        // 转换为DTO
        IPage<ProductInventoryDTO> dtoPage = inventoryPage.convert(this::convertToDTO);

        log.info("查询完成，共找到 {} 条记录", dtoPage.getTotal());
        return dtoPage;
    }

    @Override
    public ProductInventoryDTO getInventoryById(String inventoryId) {
        log.info("根据库存ID查询库存信息：{}", inventoryId);

        if (StrUtil.isBlank(inventoryId)) {
            throw new BusinessException("库存ID不能为空");
        }

        ProductInventory inventory = productInventoryMapper.selectByInventoryId(inventoryId);
        if (inventory == null) {
            throw new BusinessException("库存记录不存在");
        }

        return convertToDTO(inventory);
    }

    @Override
    public ProductInventoryDTO getInventoryByProductId(String productId) {
        log.info("根据产品ID查询库存信息：{}", productId);

        if (StrUtil.isBlank(productId)) {
            throw new BusinessException("产品ID不能为空");
        }

        ProductInventory inventory = productInventoryMapper.selectByProductId(productId);
        if (inventory == null) {
            log.warn("产品 {} 不存在库存记录", productId);
            return null;
        }

        return convertToDTO(inventory);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean createInventory(ProductInventoryDTO inventoryDTO) {
        log.info("新增产品库存：{}", inventoryDTO);

        // 检查产品ID是否为空
        if (StrUtil.isBlank(inventoryDTO.getProductId())) {
            throw new BusinessException("产品ID不能为空");
        }

        // 检查是否已存在该产品的库存记录
        int count = productInventoryMapper.countByProductId(inventoryDTO.getProductId());
        if (count > 0) {
            throw new BusinessException("该产品已存在库存记录，请直接更新库存数量");
        }

        try {
            ProductInventory inventory = convertToEntity(inventoryDTO);
            boolean result = save(inventory);

            log.info("产品库存新增{}", result ? "成功" : "失败");
            return result;
        } catch (Exception e) {
            if (e.getMessage().contains("foreign key constraint fails")) {
                throw new BusinessException("产品ID [" + inventoryDTO.getProductId() + "] 不存在，请确认产品信息是否正确");
            }
            throw e;
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean updateInventory(ProductInventoryDTO inventoryDTO) {
        log.info("更新产品库存：{}", inventoryDTO);

        if (StrUtil.isBlank(inventoryDTO.getInventoryId())) {
            throw new BusinessException("库存ID不能为空");
        }

        ProductInventory inventory = convertToEntity(inventoryDTO);
        boolean result = updateById(inventory);

        log.info("产品库存更新{}", result ? "成功" : "失败");
        return result;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean deleteInventory(String inventoryId) {
        log.info("删除产品库存：{}", inventoryId);

        if (StrUtil.isBlank(inventoryId)) {
            throw new BusinessException("库存ID不能为空");
        }

        boolean result = removeById(inventoryId);
        log.info("产品库存删除{}", result ? "成功" : "失败");
        return result;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean batchDeleteInventory(List<String> inventoryIds) {
        log.info("批量删除产品库存，数量：{}", inventoryIds.size());

        if (inventoryIds == null || inventoryIds.isEmpty()) {
            throw new BusinessException("删除的库存ID列表不能为空");
        }

        boolean result = removeByIds(inventoryIds);
        log.info("批量删除产品库存{}", result ? "成功" : "失败");
        return result;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean updateWipQuantity(String productId, BigDecimal wipQuantity, String reason) {
        log.info("更新在制品数量，产品ID：{}，数量：{}，原因：{}", productId, wipQuantity, reason);

        if (wipQuantity.compareTo(BigDecimal.ZERO) < 0) {
            throw new BusinessException("在制品数量不能为负数");
        }

        int result = productInventoryMapper.updateWipQuantity(productId, wipQuantity);
        boolean success = result > 0;

        log.info("在制品数量更新{}", success ? "成功" : "失败");
        return success;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean updateFinishedQuantity(String productId, BigDecimal finishedQuantity, String reason) {
        log.info("更新完成品数量，产品ID：{}，数量：{}，原因：{}", productId, finishedQuantity, reason);

        if (finishedQuantity.compareTo(BigDecimal.ZERO) < 0) {
            throw new BusinessException("完成品数量不能为负数");
        }

        int result = productInventoryMapper.updateFinishedQuantity(productId, finishedQuantity);
        boolean success = result > 0;

        log.info("完成品数量更新{}", success ? "成功" : "失败");
        return success;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean transferWipToFinished(String productId, BigDecimal quantity, String reason) {
        log.info("在制品转完成品，产品ID：{}，数量：{}，原因：{}", productId, quantity, reason);

        ProductInventory inventory = productInventoryMapper.selectByProductId(productId);
        if (inventory == null) {
            throw new BusinessException("产品库存记录不存在");
        }

        if (inventory.getWipQuantity().compareTo(quantity) < 0) {
            throw new BusinessException("在制品数量不足，无法转换");
        }

        // 减少在制品数量，增加完成品数量
        BigDecimal newWipQuantity = inventory.getWipQuantity().subtract(quantity);
        BigDecimal newFinishedQuantity = inventory.getFinishedQuantity().add(quantity);

        inventory.setWipQuantity(newWipQuantity);
        inventory.setFinishedQuantity(newFinishedQuantity);

        boolean result = updateById(inventory);
        log.info("在制品转完成品{}", result ? "成功" : "失败");
        return result;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean addToWip(String productId, BigDecimal quantity, String reason) {
        log.info("投入生产，产品ID：{}，数量：{}，原因：{}", productId, quantity, reason);

        if (quantity.compareTo(BigDecimal.ZERO) <= 0) {
            throw new BusinessException("投入数量必须大于0");
        }

        ProductInventory inventory = productInventoryMapper.selectByProductId(productId);
        if (inventory == null) {
            throw new BusinessException("产品库存记录不存在");
        }

        BigDecimal newWipQuantity = inventory.getWipQuantity().add(quantity);
        return updateWipQuantity(productId, newWipQuantity, reason);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean completeProduction(String productId, BigDecimal quantity, String reason) {
        log.info("完成生产，产品ID：{}，数量：{}，原因：{}", productId, quantity, reason);

        if (quantity.compareTo(BigDecimal.ZERO) <= 0) {
            throw new BusinessException("完成数量必须大于0");
        }

        return transferWipToFinished(productId, quantity, reason);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean shipProduct(String productId, BigDecimal quantity, String reason) {
        log.info("产品出库，产品ID：{}，数量：{}，原因：{}", productId, quantity, reason);

        if (quantity.compareTo(BigDecimal.ZERO) <= 0) {
            throw new BusinessException("出库数量必须大于0");
        }

        ProductInventory inventory = productInventoryMapper.selectByProductId(productId);
        if (inventory == null) {
            throw new BusinessException("产品库存记录不存在");
        }

        if (inventory.getFinishedQuantity().compareTo(quantity) < 0) {
            throw new BusinessException("完成品库存不足，无法出库");
        }

        BigDecimal newFinishedQuantity = inventory.getFinishedQuantity().subtract(quantity);
        return updateFinishedQuantity(productId, newFinishedQuantity, reason);
    }

    @Override
    public List<ProductInventoryDTO> getInventorySummary() {
        log.info("获取库存汇总信息");

        List<ProductInventory> inventoryList = productInventoryMapper.selectInventorySummary();
        List<ProductInventoryDTO> dtoList = inventoryList.stream()
                .map(this::convertToDTO)
                .collect(Collectors.toList());

        log.info("查询完成，共找到 {} 个产品库存", dtoList.size());
        return dtoList;
    }

    @Override
    public boolean checkFinishedInventorySufficient(String productId, BigDecimal requiredQuantity) {
        log.info("检查完成品库存是否充足，产品ID：{}，所需数量：{}", productId, requiredQuantity);

        ProductInventory inventory = productInventoryMapper.selectByProductId(productId);
        if (inventory == null) {
            log.warn("产品 {} 不存在库存记录", productId);
            return false;
        }

        boolean sufficient = inventory.getFinishedQuantity().compareTo(requiredQuantity) >= 0;
        log.info("完成品库存检查结果：{}", sufficient ? "充足" : "不足");
        return sufficient;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean decreaseWipQuantity(String productId, BigDecimal amount, String reason) {
        log.info("减少在制品数量，产品ID：{}，数量：{}，原因：{}", productId, amount, reason);

        if (amount.compareTo(BigDecimal.ZERO) <= 0) {
            throw new BusinessException("减少数量必须大于0");
        }

        ProductInventory inventory = productInventoryMapper.selectByProductId(productId);
        if (inventory == null) {
            throw new BusinessException("产品库存记录不存在");
        }

        if (inventory.getWipQuantity().compareTo(amount) < 0) {
            throw new BusinessException("在制品数量不足，无法减少");
        }

        BigDecimal newWipQuantity = inventory.getWipQuantity().subtract(amount);
        return updateWipQuantity(productId, newWipQuantity, reason);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean increaseFinishedQuantity(String productId, BigDecimal amount, String reason) {
        log.info("增加完成品数量，产品ID：{}，数量：{}，原因：{}", productId, amount, reason);

        if (amount.compareTo(BigDecimal.ZERO) <= 0) {
            throw new BusinessException("增加数量必须大于0");
        }

        ProductInventory inventory = productInventoryMapper.selectByProductId(productId);
        if (inventory == null) {
            throw new BusinessException("产品库存记录不存在");
        }

        BigDecimal newFinishedQuantity = inventory.getFinishedQuantity().add(amount);
        return updateFinishedQuantity(productId, newFinishedQuantity, reason);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean decreaseFinishedQuantity(String productId, BigDecimal amount, String reason) {
        log.info("减少完成品数量，产品ID：{}，数量：{}，原因：{}", productId, amount, reason);

        if (amount.compareTo(BigDecimal.ZERO) <= 0) {
            throw new BusinessException("减少数量必须大于0");
        }

        ProductInventory inventory = productInventoryMapper.selectByProductId(productId);
        if (inventory == null) {
            throw new BusinessException("产品库存记录不存在");
        }

        if (inventory.getFinishedQuantity().compareTo(amount) < 0) {
            throw new BusinessException("完成品数量不足，无法减少");
        }

        BigDecimal newFinishedQuantity = inventory.getFinishedQuantity().subtract(amount);
        return updateFinishedQuantity(productId, newFinishedQuantity, reason);
    }

    /**
     * 实体转DTO
     */
    private ProductInventoryDTO convertToDTO(ProductInventory entity) {
        ProductInventoryDTO dto = new ProductInventoryDTO();
        BeanUtil.copyProperties(entity, dto);

        // 计算总库存数量
        if (entity.getWipQuantity() != null && entity.getFinishedQuantity() != null) {
            dto.setTotalQuantity(entity.getWipQuantity().add(entity.getFinishedQuantity()));
        }

        return dto;
    }

    /**
     * DTO转实体
     */
    private ProductInventory convertToEntity(ProductInventoryDTO dto) {
        ProductInventory entity = new ProductInventory();
        BeanUtil.copyProperties(dto, entity);
        return entity;
    }
} 